﻿using Airthmetic;
using BaseTool;
using Kitware.VTK;
using System;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace StructuredLightSystemUI
{
    /// <summary>
    /// 点云显示窗体
    /// </summary>
    public partial class PointCloudForm : InnerForm
    {
        /// <summary> 3D显示 </summary>
        private RenderWindowControl renderWindowControl1 = new RenderWindowControl();
        /// <summary> 刷新显示锁 </summary>
        private readonly object lockRefreshPointCloud = new object();

        #region 构造、初始化
        /// <summary>
        /// 构造
        /// </summary>
        public PointCloudForm()
        {
            InitializeComponent();
        }
        //加载
        private void PointCloudForm_Load(object sender, EventArgs e)
        {
            renderWindowControl1.Dock = DockStyle.Fill;
            this.panelBackground.Controls.Add(renderWindowControl1);
        }
        //显示
        private void PointCloudForm_Shown(object sender, EventArgs e)
        {

        }
        //正在关闭
        private void PointCloudForm_FormClosing(object sender, FormClosingEventArgs e)
        {

        }
        //已关闭
        private void PointCloudForm_FormClosed(object sender, FormClosedEventArgs e)
        {

        }
        #endregion

        /// <summary>
        /// 显示点云
        /// </summary>
        /// <param name="plyPath"></param>
        public void ShowPly(string plyPath)
        {
            try
            {
                //1 获取点云
                Point_RGB[] rgb = GetPlyData(plyPath);
                if (rgb.Length == 0)
                    return;

                //2 转换数据
                vtkPoints pointsVtk;
                vtkUnsignedCharArray colorRGB;
                if (!TransitionType(rgb, out pointsVtk, out colorRGB))
                {
                    Log.SaveLog($"转换数据失败", LogType.Run, Color.Red);
                    return;
                }

                //3 显示点云
                ShowImage(pointsVtk, colorRGB);
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"显示点云异常，{ex.Message}");
            }
        }

        /// <summary>
        /// 1.获取数据
        /// </summary>
        /// <param name="plyPath"></param>
        /// <returns></returns>
        public static Point_RGB[] GetPlyData(string plyPath)
        {
            Point_RGB[] points = new Point_RGB[0];

            //1 读取数据
            FileInfo fi = new FileInfo(plyPath);
            if (!fi.Exists)
                return new Point_RGB[0];

            //2读取数据长度
            int startIndex = 0;
            int pointLength = 0;
            string[] AllLines = File.ReadAllLines(fi.FullName, Encoding.ASCII);
            int property = 0;
            int[] index = new int[6] { -1, -1, -1, -1, -1, -1 };
            for (; startIndex < 100; startIndex++)
            {
                //是否结束
                if (AllLines[startIndex].Contains("end_header"))
                    break;

                string[] parts = AllLines[startIndex].Split(' ');
                if (parts.Length < 2)
                    continue;
                //数据长度
                if (parts[0].Contains("element"))
                {
                    if (int.TryParse(parts[2], out pointLength))
                        points = new Point_RGB[pointLength];
                }
                //数据类型
                if (parts[0].Contains("property"))
                {
                    if (parts[2] == "x" || parts[2] == "X")
                        index[0] = property;
                    if (parts[2] == "y" || parts[2] == "Y")
                        index[1] = property;
                    if (parts[2] == "z" || parts[2] == "Z")
                        index[2] = property;
                    if (parts[2] == "red")
                        index[3] = property;
                    if (parts[2] == "green")
                        index[4] = property;
                    if (parts[2] == "blue")
                        index[5] = property;
                    property++;
                }
            }
            startIndex++;

            //3填充点云
            if (points.Length == 0)
            {
                Log.SaveLog($"数据头信息异常", LogType.Run, Color.Red);
                return new Point_RGB[0];
            }
            switch (property)
            {
                case 3:
                    {
                        //if (index[0] != 0 || index[1] != 1 || index[2] != 2)
                        //{
                        //    Log.SaveLog($"数据头解析异常", LogType.Run, Color.Red);
                        //    return new Point_RGB[0];
                        //}
                        //Parallel.For(startIndex, AllLines.Length, (i) =>
                        //{
                        //    string[] parts = AllLines[i].Split(' ');
                        //    if (parts.Length < 3)
                        //        return;

                        //    float x, y, z;
                        //    if (float.TryParse(parts[0], out x) &&
                        //        float.TryParse(parts[1], out y) &&
                        //        float.TryParse(parts[2], out z))
                        //    {
                        //        points[i - startIndex] = new Point_RGB() { X = x, Y = y, Z = z, Red = 255, Green = 255, Blue = 255 };
                        //    }
                        //});
                        break;
                    }
                case 6:
                    {
                        if (index[0] != 0 || index[1] != 1 || index[2] != 2)
                        {
                            Log.SaveLog($"数据头解析异常", LogType.Run, Color.Red);
                            return new Point_RGB[0];
                        }

                        if (index[3] != 3 || index[4] != 4 || index[5] != 5)
                        {
                            Parallel.For(startIndex, AllLines.Length, (i) =>
                            {
                                string[] parts = AllLines[i].Split(' ');
                                if (parts.Length < 3)
                                    return;

                                int nowIndex = (i - startIndex - (i - startIndex) % 2) / 2;
                                if ((i - startIndex) % 2 == 0)
                                {
                                    float x, y, z;
                                    if (float.TryParse(parts[0], out x) &&
                                        float.TryParse(parts[1], out y) &&
                                        float.TryParse(parts[2], out z))
                                    {
                                        points[nowIndex] = new Point_RGB() { X = x, Y = y, Z = z, Red = 255, Green = 255, Blue = 255 };
                                    }
                                }
                            });
                        }
                        else
                        {
                            Parallel.For(startIndex, AllLines.Length, (i) =>
                            {
                                string[] parts = AllLines[i].Split(' ');
                                if (parts.Length < 3)
                                    return;

                                int nowIndex = (i - startIndex - (i - startIndex) % 2) / 2;
                                if (points[nowIndex] == null)
                                    points[nowIndex] = new Point_RGB();
                                if ((i - startIndex) % 2 == 0)
                                {
                                    float x, y, z;
                                    if (float.TryParse(parts[0], out x) &&
                                            float.TryParse(parts[1], out y) &&
                                            float.TryParse(parts[2], out z))
                                    {
                                        points[nowIndex].X = x;
                                        points[nowIndex].Y = y;
                                        points[nowIndex].Z = z;
                                    }
                                }
                                else
                                {
                                    byte r, g, b;
                                    if (byte.TryParse(parts[0], out r) &&
                                            byte.TryParse(parts[1], out g) &&
                                            byte.TryParse(parts[2], out b))
                                    {
                                        points[nowIndex].Red = r;
                                        points[nowIndex].Green = g;
                                        points[nowIndex].Blue = b;
                                    }
                                }
                            });
                        }
                        break;
                    }
                case 9:
                    {
                        //if (index[0] != 0 || index[1] != 1 || index[2] != 2)
                        //{
                        //    Log.SaveLog($"数据头解析异常", LogType.Run, Color.Red);
                        //    return new Point_RGB[0];
                        //}
                        //if (index[3] != 6 || index[4] != 7 || index[5] != 8)
                        //{
                        //    Parallel.For(startIndex, AllLines.Length, (i) =>
                        //    {
                        //        string[] parts = AllLines[i].Split(' ');
                        //        if (parts.Length < 3)
                        //            return;

                        //        int nowIndex = (i - startIndex - (i - startIndex) % 3) / 3;
                        //        if ((i - startIndex) % 3 == 0)
                        //        {
                        //            float x, y, z;
                        //            if (float.TryParse(parts[0], out x) &&
                        //                float.TryParse(parts[1], out y) &&
                        //                float.TryParse(parts[2], out z))
                        //            {
                        //                points[nowIndex] = new Point_RGB() { X = x, Y = y, Z = z, Red = 255, Green = 255, Blue = 255 };
                        //            }
                        //        }
                        //    });
                        //}
                        //else
                        //{
                        //    Parallel.For(startIndex, AllLines.Length, (i) =>
                        //    {
                        //        string[] parts = AllLines[i].Split(' ');
                        //        if (parts.Length < 3)
                        //            return;

                        //        int nowIndex = (i - startIndex - (i - startIndex) % 3) / 3;
                        //        if (points[nowIndex] == null)
                        //            points[nowIndex] = new Point_RGB();
                        //        if ((i - startIndex) % 3 == 0)
                        //        {
                        //            float x, y, z;
                        //            if (float.TryParse(parts[0], out x) &&
                        //                float.TryParse(parts[1], out y) &&
                        //                float.TryParse(parts[2], out z))
                        //            {
                        //                points[nowIndex].X = x;
                        //                points[nowIndex].Y = y;
                        //                points[nowIndex].Z = z;
                        //            }
                        //        }
                        //        else if ((i - startIndex) % 3 == 2)
                        //        {
                        //            byte r, g, b;
                        //            if (byte.TryParse(parts[0], out r) &&
                        //                byte.TryParse(parts[1], out g) &&
                        //                byte.TryParse(parts[2], out b))
                        //            {
                        //                points[nowIndex].Red = r;
                        //                points[nowIndex].Green = g;
                        //                points[nowIndex].Blue = b;
                        //            }
                        //        }
                        //    });
                        //}
                        break;
                    }
            }

            return points;
        }

        /// <summary>
        /// 2.转换数据
        /// </summary>
        /// <param name="pointsRGB"></param>
        /// <param name="pointsVtk"></param>
        /// <param name="colorRGB"></param>
        /// <returns></returns>
        public static bool TransitionType(Point_RGB[] pointsRGB, out vtkPoints pointsVtk, out vtkUnsignedCharArray colorRGB)
        {
            try
            {
                //1初始化
                pointsVtk = new vtkPoints();
                colorRGB = vtkUnsignedCharArray.New();
                colorRGB.SetNumberOfComponents(3);

                //2转换数据
                for (int i = 0; i < pointsRGB.Length; i++)
                {
                    pointsVtk.InsertPoint(i, pointsRGB[i].X, pointsRGB[i].Y, pointsRGB[i].Z);
                    colorRGB.InsertNextTuple3(pointsRGB[i].Red, pointsRGB[i].Green, pointsRGB[i].Blue);
                }
                return true;
            }
            catch (Exception ex)
            {
                Log.SaveError(ex);
                pointsVtk = null;
                colorRGB = null;
                return false;
            }
        }

        /// <summary>
        /// 3.显示原图
        /// </summary>
        /// <param name="points">点云数据</param>
        /// <param name="colorRGB">彩色数据</param>
        private void ShowImage(vtkPoints points, vtkUnsignedCharArray colorRGB)
        {
            try
            {
                lock (lockRefreshPointCloud)
                {
                    //显示彩色点云
                    ShowColorfulPointCloud(renderWindowControl1, points, colorRGB);
                    this.Text = $"点云显示（Point：{points.GetNumberOfPoints()}）";
                }
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"点云显示异常，{ex.Message}");
            }
        }

        /// <summary>
        /// 4.显示彩色点云
        /// </summary>
        /// <param name="control"></param>
        /// <param name="points"></param>
        /// <param name="colorRGB"></param>
        private void ShowColorfulPointCloud(
            RenderWindowControl control,
            vtkPoints points,
            vtkUnsignedCharArray colorRGB)
        {
            //清空点云
            vtkRenderer render = control.RenderWindow.GetRenderers().GetFirstRenderer();
            for (int i = 0; i < render.GetActors().GetNumberOfItems(); i++)
            {
                var item = render.GetActors().GetItemAsObject(i);
                render.RemoveActor((vtkActor)item);
                item.Dispose();
            }

            //初始化点云数据
            vtkPolyData polydata = vtkPolyData.New();
            //设置点云数据
            polydata.SetPoints(points);
            //设置点云的渲染标量
            polydata.GetPointData().SetScalars(colorRGB);

            //初始化顶点过滤器
            vtkVertexGlyphFilter glyphFilter = vtkVertexGlyphFilter.New();
            //设置顶点过滤器
            glyphFilter.SetInputConnection(polydata.GetProducerPort());

            //初始化多边形数据映射
            vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
            //设置管线连接
            mapper.SetInputConnection(glyphFilter.GetOutputPort());
            //开启颜色渲染
            mapper.ScalarVisibilityOn();
            //设置渲染范围
            mapper.SetScalarRange(0, 500);

            //初始化图形渲染对象
            vtkActor actor = vtkActor.New();
            //设置数据映射
            actor.SetMapper(mapper);

            //控件添加渲染对象
            render.AddActor(actor);
            render.SetViewport(0.0, 0.0, 1, 1);
            render.ResetCamera();
            control.Refresh();
        }
    }
}
